<template>
    <view class="mask" :class="!show ? '' : 'mask-show'" :style="{ backgroundColor: show ? maskBg : 'rgba(0,0,0,0)' }"
        @tap="tapMask">
        <view class="popups" :class="[theme]" :style="{ top: popupsTop, left: popupsLeft, flexDirection: direction }">
            <text :class="dynPlace" :style="{ width: '0px', height: '0px' }" v-if="triangle"></text>
            <view v-for="(item, index) in popData" :key="index" @tap.stop="tapItem(item)" class="itemChild view"
                :class="[direction == 'row' ? 'solid-right' : 'solid-bottom', item.disabled ? 'disabledColor' : '']">
                <image class="image" :src="item.icon" v-if="item.icon"></image>{{ item.title }}
            </view>
            <slot></slot>
        </view>
    </view>
</template>

<script setup>
import { ref, watch, onMounted, computed, getCurrentInstance } from 'vue';

const props = defineProps({
    modelValue: {
        type: Boolean,
        default: false
    },
    maskBg: {
        type: String,
        default: 'rgba(0,0,0,0)'
    },
    placement: {
        type: String,
        default: 'default' //default top-start top-end bottom-start bottom-end 
    },
    direction: {
        type: String,
        default: 'column' //column row
    },
    x: {
        type: Number,
        default: 0
    },
    y: {
        type: Number,
        default: 0
    },
    popData: {
        type: Array,
        default: () => []
    },
    theme: {
        type: String,
        default: 'light' //light dark
    },
    dynamic: {
        type: Boolean,
        default: true
    },
    gap: {
        type: Number,
        default: 20
    },
    triangle: {
        type: Boolean,
        default: true
    }
});

const emit = defineEmits(['update:modelValue', 'tapPopup']);
const instance = getCurrentInstance();
const popupsTop = ref('0rpx');
const popupsLeft = ref('0rpx');
const show = ref(false);
const dynPlace = ref('');

// Computed
const dynPlaceComputed = computed(() => {
    return props.placement === 'default' ? '' : props.placement;
});

// Methods
const tapMask = () => emit('update:modelValue', !props.modelValue);

const tapItem = (item) => {
    if (item.disabled) return;
    emit('tapPopup', item);
    emit('update:modelValue', !props.modelValue);
};

const getStatusBar = () => {
    return new Promise((resolve, reject) => {
        uni.getSystemInfo({
            success: function (e) {
                let customBar
                // #ifdef H5
                customBar = e.statusBarHeight + e.windowTop;
                // #endif
                resolve(customBar)
            }
        })
    })
};

const popupsPosition = async () => {
    let statusBar = await getStatusBar()
    return new Promise((resolve, reject) => {
        let popupsDom = uni.createSelectorQuery().in(instance).select(".popups")
        popupsDom.fields({
            size: true,
        }, (data) => {
            let width = data.width
            let height = data.height

            let y = props.dynamic ? dynamicGetY(props.y, props.gap) : transformRpx(props.y)

            let x = props.dynamic ? dynamicGetX(props.x, props.gap) : transformRpx(props.x)

            // #ifdef H5
            y = props.dynamic ? (props.y + statusBar) : transformRpx(props.y + statusBar)
            // #endif 

            dynPlace.value = props.placement == 'default' ? getPlacement(x, y) : props.placement

            switch (dynPlace.value) {
                case 'top-start':
                    popupsTop.value = `${y + 9}px`
                    popupsLeft.value = `${x - 15}px`
                    break;
                case 'top-end':
                    popupsTop.value = `${y + 9}px`
                    popupsLeft.value = `${x + 15 - width}px`
                    break;
                case 'bottom-start':
                    popupsTop.value = `${y - 18 - height}px`
                    popupsLeft.value = `${x - 15}px`
                    break;
                case 'bottom-end':
                    popupsTop.value = `${y - 9 - height}px`
                    popupsLeft.value = `${x + 15 - width}px`
                    break;
            }
            resolve()
        }).exec();

    })
};

const getPlacement = (x, y) => {
    let width = uni.getSystemInfoSync().windowWidth
    let height = uni.getSystemInfoSync().windowHeight
    if (x > width / 2 && y > height / 2) {
        return 'bottom-end'
    } else if (x < width / 2 && y < height / 2) {
        return 'top-start'
    } else if (x > width / 2 && y < height / 2) {
        return 'top-end'
    } else if (x < width / 2 && y > height / 2) {
        return 'bottom-start'
    } else if (x > width / 2) {
        return 'top-end'
    } else {
        return 'top-start'
    }
};

const dynamicGetY = (y, gap) => {
    let height = uni.getSystemInfoSync().windowHeight
    y = y < gap ? gap : y
    y = height - y < gap ? (height - gap) : y
    return y
};

const dynamicGetX = (x, gap) => {
    let width = uni.getSystemInfoSync().windowWidth
    x = x < gap ? gap : x
    x = width - x < gap ? (width - gap) : x
    return x
};

const transformRpx = (params) => {
    return params * uni.getSystemInfoSync().screenWidth / 375
};

// Watchers
watch(
    () => props.modelValue,
    async (newVal) => {
        if (newVal) await popupsPosition();
        show.value = newVal;
    },
    { immediate: true }
);

watch(
    () => props.placement,
    (newVal) => {
        dynPlace.value = newVal;
    },
    { immediate: true }
);

// Lifecycle
onMounted(() => {
    popupsPosition();
});
</script>

<style lang="scss" scoped>
.mask {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 9999;
    transition: background 0.3s ease-in-out;
    visibility: hidden;

    &.mask-show {
        visibility: visible;
    }
}

.popups {
    position: absolute;
    padding: 5rpx;
    border-radius: 5px;
    display: flex;

    .view {
        padding: 10rpx;
    }

    .image {
        display: inline-block;
        vertical-align: middle;
        width: 40rpx;
        height: 40rpx;
        margin-right: 20rpx;
    }
}

.dark {
    background-color: #4C4C4C;
    color: #fff;

    .top-start:after {
        content: "";
        position: absolute;
        top: -18rpx;
        left: 10rpx;
        border-width: 0 20rpx 20rpx;
        border-style: solid;
        border-color: transparent transparent #4C4C4C;
    }

    .top-end:after {
        content: "";
        position: absolute;
        top: -18rpx;
        right: 10rpx;
        border-width: 0 20rpx 20rpx;
        border-style: solid;
        border-color: transparent transparent #4C4C4C;
    }

    .bottom-start:after {
        content: "";
        position: absolute;
        bottom: -18rpx;
        left: 10rpx;
        border-width: 20rpx 20rpx 0;
        border-style: solid;
        border-color: #4C4C4C transparent transparent;
    }

    .bottom-end:after {
        content: "";
        position: absolute;
        bottom: -18rpx;
        right: 10rpx;
        border-width: 20rpx 20rpx 0;
        border-style: solid;
        border-color: #4C4C4C transparent transparent;
    }

    .disabledColor {
        color: #c5c8ce;
    }
}

.light {
    color: #515a6e;
    box-shadow: 0upx 0upx 30upx rgba(0, 0, 0, 0.2);
    background: #fff;

    .top-start:after {
        content: "";
        position: absolute;
        top: -18rpx;
        left: 10rpx;
        border-width: 0 20rpx 20rpx;
        border-style: solid;
        border-color: transparent transparent #fff;
    }

    .top-end:after {
        content: "";
        position: absolute;
        top: -18rpx;
        right: 10rpx;
        border-width: 0 20rpx 20rpx;
        border-style: solid;
        border-color: transparent transparent #fff;
    }

    .bottom-start:after {
        content: "";
        position: absolute;
        bottom: -18rpx;
        left: 10rpx;
        border-width: 20rpx 20rpx 0;
        border-style: solid;
        border-color: #fff transparent transparent;
    }

    .bottom-end:after {
        content: "";
        position: absolute;
        bottom: -18rpx;
        right: 10rpx;
        border-width: 20rpx 20rpx 0;
        border-style: solid;
        border-color: #fff transparent transparent;
    }

    .disabledColor {
        color: #c5c8ce;
    }
}

.solid-bottom {
    border-bottom: 1px solid #ccc;
}

.solid-right {
    border-right: 1px solid #ccc;
}

.popups .itemChild:last-child {
    border: none;
}
</style>
